#ifndef THREADS_THREAD_H
#define THREADS_THREAD_H

#include <debug.h>
#include <list.h>
#include <stdint.h>
#include "threads/fixed_point.h"

enum thread_status {
    THREAD_RUNNING,
    THREAD_READY,
    THREAD_BLOCKED,
    THREAD_DYING
};


typedef int tid_t;
#define TID_ERROR ((tid_t) -1)

#define PRI_MIN 0
#define PRI_DEFAULT 31
#define PRI_MAX 63

struct thread {
    tid_t tid;
    enum thread_status status;
    char name[16];
    uint8_t *stack;
    int priority;
    struct list_elem allelem;

    struct list_elem elem;

#ifdef USERPROG
    uint32_t *pagedir;
#endif

    unsigned magic;

//  1
    int64_t ticks_blocked;
//  2
    int base_priority;
    struct list locks;
    struct lock *lock_waiting;
//  3
    int nice;
    fixed_t recent_cpu;
};


extern bool thread_mlfqs;

void thread_init(void);

void thread_start(void);

void thread_tick(void);

void thread_print_stats(void);

typedef void thread_func(void *aux);

tid_t thread_create(const char *name, int priority, thread_func *, void *);

void thread_block(void);

void thread_unblock(struct thread *);

struct thread *thread_current(void);

tid_t thread_tid(void);

const char *thread_name(void);

void thread_exit(void)

NO_RETURN;

void thread_yield(void);

typedef void thread_action_func(struct thread *t, void *aux);

void thread_foreach(thread_action_func *, void *);

int thread_get_priority(void);

void thread_set_priority(int);

int thread_get_nice(void);

void thread_set_nice(int);

int thread_get_recent_cpu(void);

int thread_get_load_avg(void);

// 1

void blocked_thread_check(struct thread *t, void *aux UNUSED);

// 2

bool thread_cmp_priority(const struct list_elem *a, const struct list_elem *b, void *aux UNUSED);

bool lock_cmp_priority(const struct list_elem *a, const struct list_elem *b, void *aux UNUSED);

void thread_hold_the_lock(struct lock *lock);

void thread_remove_lock(struct lock *lock);

void thread_donate_priority(struct thread *t);

void thread_update_priority(struct thread *t);

// 3

void thread_mlfqs_increase_recent_cpu_by_one(void);

void thread_mlfqs_update_load_avg_and_recent_cpu(void);

void thread_mlfqs_update_priority(struct thread *t);

#endif /* threads/thread.h */
